﻿using Koala.Pro.Common;
using Koala.Pro.Core;
using Koala.Pro.Core.Dto;
using Koala.Pro.Core.Models;
using SqlSugar;

namespace Koala.Pro.Services
{
    public class FunctionService : MyCrudService<FunctionInfo, string, FunctionPagedDto>, IFunctionService, IMyCrudService<FunctionInfo, string, FunctionPagedDto>, ITransientDependency, IDependency
    {
        private Dictionary<string, string> FunctionNameDict = new Dictionary<string, string>
        {
            { "Add", "添加" },
            { "Delete", "删除" },
            { "Edit", "修改" },
            { "View", "查看" },
            { "Import", "导入" },
            { "Export", "导出" }
        };

        private IRoleService _roleService;

        public FunctionService(IApiUserSession currentApiUser, IRoleService roleService)
        {
            base.CurrentApiUser = currentApiUser;
            _roleService = roleService;
        }

        public override Task<Dictionary<string, string>> GetColumnNameAlias()
        {
            return Task.FromResult(new Dictionary<string, string>
            {
                { "PID", "父ID" },
                { "Name", "功能名称" },
                { "ControlID", "权限标识" },
                { "SystemType_ID", "系统编号" },
                { "SortCode", "排序码" }
            });
        }

        protected override ISugarQueryable<FunctionInfo> CreateFilteredQueryAsync(FunctionPagedDto input)
        {
            return base.CreateFilteredQueryAsync(input).WhereIF(!input.ExcludeId.IsNullOrWhiteSpace(), (FunctionInfo t) => t.Id != input.ExcludeId).WhereIF(!input.PID.IsNullOrWhiteSpace(), (FunctionInfo s) => s.PID == input.PID)
                .WhereIF(!input.Name.IsNullOrWhiteSpace(), (FunctionInfo t) => t.Name.Contains(input.Name))
                .WhereIF(!input.ControlID.IsNullOrWhiteSpace(), (FunctionInfo t) => t.ControlID.Contains(input.ControlID))
                .WhereIF(!input.SystemType_ID.IsNullOrWhiteSpace(), (FunctionInfo t) => t.SystemType_ID.Contains(input.SystemType_ID))
                .WhereIF(!input.SortCode.IsNullOrWhiteSpace(), (FunctionInfo t) => t.SortCode.Contains(input.SortCode));
        }

        protected override ISugarQueryable<FunctionInfo> ApplyDefaultSorting(ISugarQueryable<FunctionInfo> query)
        {
            return query.OrderBy((FunctionInfo s) => s.SortCode + 1);
        }

        public override async Task<bool> DeleteAsync(string id)
        {
            if (!string.IsNullOrEmpty(id))
            {
                FunctionInfo info = await GetAsync(id);
                ListResultDto<FunctionInfo> listResultDto = await GetAllAsync((FunctionInfo s) => s.PID == id);
                if (listResultDto != null && listResultDto.Items?.Count > 0)
                {
                    foreach (FunctionInfo item in listResultDto.Items)
                    {
                        item.PID = info.PID;
                        await UpdateAsync(item);
                    }
                }
                await base.DeleteAsync(id);
                return true;
            }
            return false;
        }

        public async Task<List<FunctionInfo>> GetFunctions(string roleIDs, string typeID)
        {
            List<string> roleIdList = roleIDs?.Split([',']).ToList();
            if (roleIdList != null)
            {
                return await (from t in (from t in base.Client
                                         .Queryable((FunctionInfo t, Role_FunctionInfo m) => t.Id == m.Function_ID && roleIdList.Contains(m.Role_ID.ToString()))
                                         .WhereIF(!typeID.IsNullOrWhiteSpace(), (FunctionInfo t) => t.SystemType_ID == typeID)
                                         select (t)).Distinct()
                              orderby t.SortCode
                              select t).ToListAsync();
            }
            return new List<FunctionInfo>();
        }

        public async Task<List<FunctionInfo>> GetFunctionNodes(string roleIDs, string typeID)
        {
            ISqlSugarClient sqlSugarClient = base.Client.GetSimpleClient<FunctionInfo>().AsSugarClient();
            List<string> roleIdList = roleIDs?.Split([',']).ToList();
            if (roleIdList != null)
            {
                return await (from t in (from t in sqlSugarClient.Queryable((FunctionInfo t, Role_FunctionInfo m) => t.Id == m.Function_ID && roleIdList.Contains(m.Role_ID.ToString())).WhereIF(!typeID.IsNullOrWhiteSpace(), (FunctionInfo t) => t.SystemType_ID == typeID)
                                         select (t)).Distinct()
                              orderby t.SortCode
                              select t).ToTreeAsync((FunctionInfo t) => t.Children, (FunctionInfo t) => t.PID, "-1");
            }
            return new List<FunctionInfo>();
        }

        public async Task<List<FunctionInfo>> GetFunctionNodesByPID(string pid, string typeID)
        {
            return await (from t in base.Client.GetSimpleClient<FunctionInfo>().AsSugarClient().Queryable<FunctionInfo>()
                    .WhereIF(!typeID.IsNullOrWhiteSpace(), (FunctionInfo t) => t.SystemType_ID == typeID)
                          orderby t.SortCode
                          select t).ToTreeAsync((FunctionInfo t) => t.Children, (FunctionInfo t) => t.PID, pid);
        }

        public async Task<List<FunctionInfo>> GetFunctionsByRole(int roleID, string typeID)
        {
            return await GetFunctions(roleID.ToString(), typeID);
        }

        public async Task<List<FunctionInfo>> GetFunctionsByUser(int userID, string typeID)
        {
            List<FunctionInfo> list = new List<FunctionInfo>();
            List<RoleInfo> list2 = await _roleService.GetRolesByUser(userID);
            if (list2 != null && list2.Count > 0)
            {
                string text = string.Join(",", list2.Select((RoleInfo s) => s.Id));
                text = text.Trim([',']);
                list = await GetFunctions(text, typeID);
            }
            return list;
        }

        public async Task<List<FunctionInfo>> GetFunctionNodesByUser(int userID, string typeID)
        {
            List<FunctionInfo> list = new List<FunctionInfo>();
            List<RoleInfo> list2 = await _roleService.GetRolesByUser(userID);
            if (list2 != null && list2.Count > 0)
            {
                string text = string.Join(",", list2.Select((RoleInfo s) => s.Id));
                text = text.Trim([',']);
                list = await GetFunctionNodes(text, typeID);
            }
            return list;
        }

        public async Task<bool> DeleteWithSubNode(string mainID)
        {
            IEnumerable<FunctionInfo> links = GetLinks(await base.Client.GetSimpleClient<FunctionInfo>().AsSugarClient().Queryable<FunctionInfo>()
                .ToTreeAsync((FunctionInfo t) => t.Children, (FunctionInfo t) => t.PID, mainID));
            IEnumerable<string> flattenIds = links.Select((FunctionInfo s) => s.Id);
            return await DeleteAsync((FunctionInfo s) => flattenIds.Contains(s.Id));
        }

        public async Task<List<FunctionInfo>> GetTree(string systemType)
        {
            string pid = "-1";
            return await GetFunctionNodesByPID(pid, systemType);
        }

        public async Task<List<FunctionInfo>> GetTreeByID(string mainID)
        {
            return await GetFunctionNodesByPID(mainID, "");
        }

        public async Task<bool> BatchAdd(BatchAddFunctionDto input)
        {
            bool result = await InsertAsync(input);
            if (result)
            {
                int index = 0;
                foreach (string item in input?.SubFunctions)
                {
                    FunctionNameDict.TryGetValue(item, out var value);
                    FunctionInfo input2 = new FunctionInfo
                    {
                        Id = Guid.NewGuid().ToString(),
                        PID = input.Id,
                        SystemType_ID = input.SystemType_ID,
                        ControlID = input.ControlID + ":" + item,
                        Name = value + input.Name,
                        SortCode = index++.ToString().PadLeft(3, '0')
                    };
                    await InsertAsync(input2);
                }
            }
            return result;
        }

        public async Task<ListResultDto<FunctionInfo>> GetAllBySystemType(string systemType)
        {
            return await base.GetAllAsync((FunctionInfo s) => s.SystemType_ID == systemType);
        }

        private IEnumerable<FunctionInfo> GetLinks(IEnumerable<FunctionInfo> list)
        {
            foreach (FunctionInfo node in list)
            {
                yield return node;
                foreach (FunctionInfo link in GetLinks(node.Children))
                {
                    yield return link;
                }
            }
        }
    }
}
